package com.hopscotch.interceptor;

import com.hopscotch.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
;

/**

 * 它会确保对每个 HTTP 请求仅执行一次过滤逻辑，避免因请求转发、包含等场景导致的重复处理，
 * 保证认证逻辑的唯一性和效率。
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtils jwtUtils;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获得令牌
        String token = jwtUtils.getToken(request);

        // 如果有令牌,将用户信息放到security中
        if (StringUtils.hasText(token)){
            Claims claims = null;
            try {
                // 解析获得claims
                claims = jwtUtils.parserToken(token);
            }catch (Exception e){
                e.printStackTrace();
                log.debug("令牌解析出错");
            }
            String redisToken = null;
            try {
                redisToken = jwtUtils.getRedisToken((String) claims.get("uid"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (!token.equals(redisToken)){
                filterChain.doFilter(request, response);
                return;
            }
            // 从claims中获取权限和用户名
            String username = claims.get("username", String.class);
            List perms = claims.get("perms", List.class);
            String permsStr = String.join(",", perms);
            List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(permsStr);

            // 创建对象
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(username,null, authorityList);

            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 放入上下文
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        // 放行
        // 如果没有令牌,放行到后续的security的认证拦截机制
        // 令牌不存在、格式错误或验证失败，通常会跳过认证（不注入上下文），让请求继续流转到后续的安全组件（如 ExceptionTranslationFilter）处理，最终可能返回 401（未认证）或 403（权限不足）响应。
        filterChain.doFilter(request, response);
    }
}
